#include "load_json_file.h"
#include <json/json.h>
#include <json/reader.h>
#include <iostream>
#include <dbms/dbms_channel.h>
#include <dbms/dbms_device.h>

namespace iot_acq {
LoadJsonFile::LoadJsonFile() {}

LoadJsonFile::~LoadJsonFile() {}

bool LoadJsonFile::LoadJson(const std::string &filePath, Json::Value &root)
{
	Json::Reader reader;
	std::ifstream file(filePath);
	if (!file.is_open()) {
		HTELINK_LOG_ERR("load file %s filed", filePath);
		return false;
	}
	if (!reader.parse(file, root)) {
		HTELINK_LOG_ERR("Parse error: %s", reader.getFormattedErrorMessages());
		file.close();
		return false;
	}
	file.close();
	return true;
}
bool LoadJsonFile::ParseJson(const Json::Value &root)
{
	if (root.isMember("channels")) {
		if (!ParseChannels(root["channels"])) {
			return false;
		}
	}

	if (root.isMember("devices")) {
		if (!ParseDevices(root["devices"])) {
			return false;
		}
	}
	return true;
}

bool LoadJsonFile::LoadChannelFromJson(const std::string &filePath)
{
	Json::Value root;
	if (!LoadJson(filePath, root)) {
		HTELINK_LOG_ERR("load json from file %s failed", filePath);
		return false;
	}
	if (root.isMember("channels")) {
		if (!ParseChannels(root["channels"])) {
			return false;
		}
		return true;
	}
	return false;
}

bool LoadJsonFile::LoadDevicesFromJson(const std::string &filePath)
{
	Json::Value root;
	if (!LoadJson(filePath, root)) {
		HTELINK_LOG_ERR("load json from file %s failed", filePath);
		return false;
	}
	if (root.isMember("devices")) {
		if (!ParseDevices(root["devices"])) {
			return false;
		}
		return true;
	}
	return false;
}

bool LoadJsonFile::ParseChannels(const Json::Value &jsonChn)
{
	dbms::DbmsChannel dbmsChannel;
	dbmsChannel.DeleteAll();
	auto storeChannel = [&](const Json::Value &item,
							dbms::ChannelType_t type) -> bool {
		dbms::DeviceChannel_t deviceChannel;
		deviceChannel.set_id(item["id"].asUInt());
		deviceChannel.set_timeout(item["waitTime"].asInt());
		deviceChannel.set_interval(item["intervalTime"].asInt());
		deviceChannel.set_reportperiod(item["reportPeriod"].asInt());
		deviceChannel.set_ctype(type);
		if (type == dbms::CT_COM) {
			dbms::Serial_t *serial = deviceChannel.mutable_com();
			serial->set_name(item["name"].asString());
			serial->set_baudrate(item["baudRate"].asInt());
			serial->set_stopbit(item["stopBits"].asInt());
			serial->set_parity(item["parity"].asInt());
			serial->set_databit(item["dataBits"].asInt());
		} else if (type == dbms::CT_TCP || type == dbms::CT_UDP) {
			dbms::Socket_t *socket = deviceChannel.mutable_socket();
			socket->set_ip(item["ip"].asString());
			socket->set_port(item["port"].asInt());
		} else {
			HTELINK_LOG_ERR("type %d not support", static_cast<int32_t>(type));
			return false;
		}
		return dbmsChannel.Save(deviceChannel);
	};
	if (jsonChn.isMember("serialPort")) {
		const Json::Value &serialPort = jsonChn["serialPort"];
		for (const auto &item : serialPort) {
			if (!storeChannel(item, dbms::CT_COM)) {
				HTELINK_LOG_ERR("serial channel parse error");
				return false;
			}
		}
	}
	if (jsonChn.isMember("tcp")) {
		const Json::Value &tcp = jsonChn["tcp"];
		for (const auto &item : tcp) {
			if (!storeChannel(item, dbms::CT_TCP)) {
				HTELINK_LOG_ERR("tcp channel parse error");
				return false;
			}
		}
	}

	if (jsonChn.isMember("udp")) {
		const Json::Value &udp = jsonChn["udp"];
		for (const auto &item : udp) {
			if (!storeChannel(item, dbms::CT_UDP)) {
				HTELINK_LOG_ERR("serial channel parse error");
				return false;
			}
		}
	}
	return true;
}
bool LoadJsonFile::ParseDevices(const Json::Value &jsonDevice)
{
	dbms::DbmsDevice dbmsDevice;
	dbmsDevice.DeleteAll();
	for (const auto &item : jsonDevice) {
		dbms::Device_t device;
		device.set_id(item["id"].asString());
		device.set_addr(item["address"].asString());
		device.set_name(item["name"].asString());
		device.set_channelid(item["channelId"].asInt());
		device.set_protoid(item["protocolId"].asString());
		const auto &functionsJson = item["functions"];
		for (const auto &funcJson : functionsJson) {
			dbms::Funcpoint_t *func = device.add_funclist();
			func->set_id(funcJson["id"].asString());
			func->set_type(funcJson["funcType"].asInt());
			if (funcJson.isMember("ratio")) {
				func->set_ratio(funcJson["ratio"].asFloat());
			} else {
				func->set_ratio(1);
			}
		}
		dbmsDevice.Save(device);
	}
	return true;
}
} // namespace iot_acq